> ## Documentation Index
> Fetch the complete documentation index at: https://sequence-0fb8d9e6-api_docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Web Verification Guide

> The content provides a detailed guide on verifying ownership of an Embedded Wallet address using a nonce and optional time expiry.

A common use case is that you authenticate the user on the client, but you want to also validate this token as well as corresponding user information on your backend. In this case, Sequence provides a function to retrieve a JWT which can be verified using your JWT library of choice for your given framework. Below we outline an example using our Web SDK, Wagmi, and an Express server.

<Note>
  If you're not using the Web SDK but instead working with the Embedded Wallet and TypeScript, you can go [here](/sdk/headless-wallet/verification) to see how to handle the verification process.
</Note>

<Note>
  An example client & server demonstrating the below is available [here](https://github.com/0xsequence-demos/web-sdk-id-token-verification)
</Note>

### Implementation

<Steps>
  <Step title="Request IdToken via Client">
    Once a user has authenticated with an embedded wallet on the client, simply call the corresponding function in order get a JWT from Sequence.

    ```typescript theme={null}
    import { useConnect } from "wagmi";

    type IdTokenResponse = {
      idToken: string;
      expiresIn: number;
    };

    export function GetIdToken() {
      const { connectors } = useConnect();

      const handleClick = async () => {
        const waasConnector = connectors.find(
          (connector) => "sequenceWaas" in connector
        ) as { sequenceWaas?: { getIdToken: () => Promise<IdTokenResponse> } } | undefined;

        const waas = waasConnector?.sequenceWaas;
        if (!waas) return;

        try {
          const { idToken, expiresIn } = await waas.getIdToken();
          console.log({ idToken, expiresIn });
        } catch (error) {
          console.error("Failed to get ID token:", error);
        }
      };

      return <button onClick={handleClick}>Log ID token</button>;
    }
    ```
  </Step>

  <Step title="Pass JWT to Backend">
    Make a POST request to your backend with the queried JWT.

    ```typescript theme={null}
    const response = await fetch(BACKEND_ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ sequenceToken: idToken }),
    });
    ```
  </Step>

  <Step title="Import JWT libraries and initialize JWKS">
    From our express server that the JWT was passed to, we simply import our preferred JWT library to verify the information and initialize our JWKS to verify against. It is also important to ensure that your expected audience is set correctly so that the claim will be properly verified.

    ```typescript theme={null}
    import * as jwt from "jsonwebtoken";
    import * as jwksClient from "jwks-rsa";

    ...serverConfig

    // Initialize the JWKS client
    const client = jwksClient({
      jwksUri: "https://waas.sequence.app/.well-known/jwks.json",
      cache: true,
      cacheMaxAge: 86400000, // 1 day
    });

    // Should be equal to the audience claim in the JWT that you want to verify which will be of the form https://sequence.build/project/*projectID*
    const EXPECTED_AUDIENCE = "https://sequence.build/project/*PROJECT_ID*"
    ```
  </Step>

  <Step title="Decoding JWT and Verifying Claims">
    Now we can parse the JWT, verify it against our JWKS URI, then validate any of the claims.

    ```typescript theme={null}
    const decodedToken = jwt.decode(token, { complete: true });
    if (!decodedToken || typeof decodedToken === "string") {
      throw new Error("Invalid token");
    }

    const kid = decodedToken.header.kid;
    const signingKey = await getSigningKey(kid);
    const publicKey = (
      signingKey as jwksClient.CertSigningKey | jwksClient.RsaSigningKey
    ).getPublicKey();

    console.log(EXPECTED_AUDIENCE);

    const verified = jwt.verify(token, publicKey, {
      algorithms: ["RS256"], // Specify the expected algorithm
      audience: EXPECTED_AUDIENCE, // Verify the audience claim
    });

      // Verifying Email claim
    if (!verified.email || typeof verified.email !== "string") {
      throw new Error("Invalid email claim");
    }
    ```
  </Step>

  <Step title="Update your backend">
    From here, you now have verified the information corresponding to the JWT and can safely update your backend as needed.
  </Step>
</Steps>
